package ide.ccf.ccproject.wizards.pages;

import ide.ccf.ccproject.managedbuilder.ManagedBuildWizard;
import ide.ccf.ccproject.translate.Message;

import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.cdt.ui.CDTSharedImages;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.newui.CDTPrefUtil;
import org.eclipse.cdt.ui.newui.PageLayout;
import org.eclipse.cdt.internal.ui.newui.*;
import org.eclipse.cdt.ui.wizards.CNewWizard;
import org.eclipse.cdt.ui.wizards.CWizardHandler;
import org.eclipse.cdt.ui.wizards.EntryDescriptor;
import org.eclipse.cdt.ui.wizards.IWizardItemsListListener;
import org.eclipse.cdt.ui.wizards.IWizardWithMemory;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.wizard.IWizard;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.osgi.util.TextProcessor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.AccessibleAdapter;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseTrackListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.TouchEvent;
import org.eclipse.swt.events.TouchListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.dialogs.WizardNewProjectCreationPage;

@SuppressWarnings({ "unchecked", "restriction" })
public class CCProjectWizardPage extends WizardNewProjectCreationPage implements IWizardItemsListListener{
	
	public static final String PAGE_ID = "ide.ccf.ccproject.ui.wizard.basicPage";
	
	private static final String EXTENSION_POINT_ID = "org.eclipse.cdt.ui.CDTWizard"; 
	private static final String ELEMENT_NAME = "wizard"; 
	private static final String CLASS_NAME = "class"; 
	public static final String DESC = "EntryDescriptor"; 
	
	// Widgets
	private Tree tree;
	private Composite right;
	private Button showSup;
	private Label rightLabel;

	public CWizardHandler h_selected;
	private Label categorySelectedLabel;
	
	public CCProjectWizardPage(String pageName) {
		super(pageName);
		ManagedBuildWizard.isCCFCatagory = true;
		setPageComplete(false);
	}
	
	@Override
	public void createControl(Composite parent) {
		super.createControl(parent);

		createDynamicGroup((Composite)getControl());
		switchTo(updateData(tree, right, showSup, (IWizardItemsListListener) CCProjectWizardPage.this, getWizard()),
				getDescriptor(tree));
		
		setPageComplete(validatePage());
		setErrorMessage(null);
		setMessage(null);
	}
	
	@SuppressWarnings({ "restriction" })
	private void createDynamicGroup(Composite parent) {
		Composite c = new Composite(parent, SWT.NULL);
		c.setLayoutData(new GridData(GridData.FILL_BOTH));
		c.setLayout(new GridLayout(1, true));
		
		final Group g = new Group(c,SWT.NONE);
		g.setText(Message.CCProjectWizardOnePage_0);
		GridData gd1 = new GridData(GridData.FILL_BOTH);
		gd1.heightHint = 112;
		gd1.widthHint = 380;
		g.setLayoutData(gd1);
		g.setLayout(new GridLayout(2,false));
		{
			Label l_1 = new Label(g, SWT.NONE);
			l_1.setText(Message.CCProjectWizardOnePage_1);
			l_1.setFont(g.getFont());
			l_1.setLayoutData(new GridData(GridData.BEGINNING));
			Combo c_1 = new Combo(g, SWT.BORDER);
			c_1.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			c_1.setFont(c.getFont());
			Label l_2 = new Label(g, SWT.NONE);
			l_2.setText(Message.CCProjectWizardOnePage_2);
			l_2.setFont(g.getFont());
			l_2.setLayoutData(new GridData(GridData.BEGINNING));
			Combo c_2 = new Combo(g, SWT.BORDER);
			c_2.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			c_2.setFont(g.getFont());
			
			Label l_occupy = new Label(g, SWT.RIGHT);
			l_occupy.setText("");
			
			final Label l_3 = new Label(g, SWT.RIGHT| SWT.HORIZONTAL );
			l_3.setText(Message.CCProjectWizardOnePage_3);
			l_3.setLayoutData(new GridData(GridData.FILL_BOTH));
			l_3.setFont(g.getFont());
			Color color = new Color(null, 67, 44, 255);
			l_3.setForeground(color);
			l_3.addMouseTrackListener(new MouseTrackListener(){
				public void mouseEnter(MouseEvent arg0) {
					l_3.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLUE));
					l_3.setCursor(Display.getCurrent().getSystemCursor(SWT.CURSOR_HAND));
				}
				public void mouseExit(MouseEvent arg0) {
					Color color = new Color(null, 67, 44, 255);
					l_3.setForeground(color);
				}
				public void mouseHover(MouseEvent arg0) {	
				}
			});
			l_3.addMouseListener(new MouseListener()
			{
				public void mouseDoubleClick(MouseEvent arg0) {
				}
				public void mouseDown(MouseEvent arg0) {
					
					PreferencesUtil.createPreferenceDialogOn(getShell(), "ide.ccf.ccproject.preferences.CCFPreferencePage", null, null).open();
				}
				public void mouseUp(MouseEvent arg0) {
				}
			});
		}
		
		//copy and change
		Composite c2 = new Composite(c, SWT.NULL);
		c2.setLayoutData(new GridData(GridData.FILL_BOTH));
		c2.setLayout(new GridLayout(2, true));
		{
			Label l1 = new Label(c2, SWT.NONE);
			l1.setText(Message.CCFConfigWizardPage_1);
			l1.setFont(parent.getFont());
			l1.setLayoutData(new GridData(GridData.BEGINNING));

			rightLabel = new Label(c2, SWT.NONE);
			rightLabel.setFont(parent.getFont());
			rightLabel.setLayoutData(new GridData(GridData.BEGINNING));

			tree = new Tree(c2, SWT.SINGLE | SWT.BORDER);
			tree.setLayoutData(new GridData(GridData.FILL_BOTH));
			tree.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					TreeItem[] tis = tree.getSelection();
					if (tis == null || tis.length == 0) return;
					switchTo((CWizardHandler)tis[0].getData(), (EntryDescriptor)tis[0].getData(DESC));
					setPageComplete(validatePage());
				}});
			tree.getAccessible().addAccessibleListener(new AccessibleAdapter() {
				@Override
				public void getName(AccessibleEvent e) {
					for (int i = 0; i < tree.getItemCount(); i++) {
						if (tree.getItem(i).getText().equals(e.result))
							return;
					}
					e.result = Message.CCFConfigWizardPage_1;
				}});
			right = new Composite(c2, SWT.NONE);
			right.setLayoutData(new GridData(GridData.FILL_BOTH));
			right.setLayout(new PageLayout());

			showSup = new Button(c2, SWT.CHECK);
			showSup.setText(Message.CCFMainWizardPage_0);
			GridData gd = new GridData(GridData.FILL_HORIZONTAL);
			gd.horizontalSpan = 2;
			showSup.setLayoutData(gd);
			showSup.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					if (h_selected != null)
						h_selected.setSupportedOnly(showSup.getSelection());
					switchTo(updateData(tree, right, showSup, (IWizardItemsListListener) CCProjectWizardPage.this, getWizard()),
							getDescriptor(tree));
				}});

			// restore settings from preferences
			showSup.setSelection(!CDTPrefUtil.getBool(CDTPrefUtil.KEY_NOSUPP));
		}
			//end copy
	}
	

	@Override
	public IWizardPage getNextPage() {
		return (h_selected == null) ? null : h_selected.getSpecificPage();
	}

	public URI getProjectLocation() {
		return useDefaults() ? null : getLocationURI();
	}

	/**
	 * Returns whether this page's controls currently all contain valid
	 * values.
	 *
	 * @return <code>true</code> if all controls are valid, and
	 *   <code>false</code> if at least one is invalid
	 */
	@SuppressWarnings("restriction")
	@Override
	protected boolean validatePage() {
		setMessage(null);
		if (!super.validatePage())
			return false;

		if (getProjectName().indexOf('#') >= 0) {
			setErrorMessage(Message.CCFMainWizardPage_8);
			return false;
		}

		boolean bad = true; // should we treat existing project as error

		IProject handle = getProjectHandle();
		if (handle.exists()) {
			if (getWizard() instanceof IWizardWithMemory) {
				IWizardWithMemory w = (IWizardWithMemory)getWizard();
				if (w.getLastProjectName() != null && w.getLastProjectName().equals(getProjectName()))
					bad = false;
			}
			if (bad) {
				setErrorMessage(Message.CCFMainWizardPage_1);
				return false;
			}
		}

		if (bad) { // Skip this check if project already created
			try {
				IFileStore fs;
				URI p = getProjectLocation();
				if (p == null) {
					fs = EFS.getStore(ResourcesPlugin.getWorkspace().getRoot().getLocationURI());
					fs = fs.getChild(getProjectName());
				} else
					fs = EFS.getStore(p);
				IFileInfo f = fs.fetchInfo();
				if (f.exists()) {
					if (f.isDirectory()) {
						if (f.getAttribute(EFS.ATTRIBUTE_READ_ONLY)) {
							setErrorMessage(Message.CCFMainWizardPage_2);
							return false;
						}
						else
							setMessage(Message.CCFMainWizardPage_3, IMessageProvider.WARNING);
					} else {
						setErrorMessage(Message.CCFMainWizardPage_4);
						return false;
					}
				}
			} catch (CoreException e) {
				CUIPlugin.log(e.getStatus());
			}
		}

		if (!useDefaults()) {
			IStatus locationStatus =
					ResourcesPlugin.getWorkspace().validateProjectLocationURI(handle, getLocationURI());
			if (!locationStatus.isOK()) {
				setErrorMessage(locationStatus.getMessage());
				return false;
			}
		}

		if (tree.getItemCount() == 0) {
			setErrorMessage(Message.CCFMainWizardPage_5);
			return false;
		}

		// it is not an error, but we cannot continue
		if (h_selected == null) {
			setErrorMessage(null);
			return false;
		}

		String s = h_selected.getErrorMessage();
		if (s != null) {
			setErrorMessage(s);
			return false;
		}

		setErrorMessage(null);
		return true;
	}

	/**
	 *
	 * @param tree
	 * @param right
	 * @param show_sup
	 * @param ls
	 * @param wizard
	 * @return : selected Wizard Handler.
	 */
	@SuppressWarnings("restriction")
	public static CWizardHandler updateData(Tree tree, Composite right, Button show_sup,
			IWizardItemsListListener ls, IWizard wizard) {
		// Remember selected item
		TreeItem[] selection = tree.getSelection();
		TreeItem selectedItem = selection.length > 0 ? selection[0] : null;
		String savedLabel = selectedItem != null ? selectedItem.getText() : null;
		String savedParentLabel = getParentText(selectedItem);

		tree.removeAll();
		IExtensionPoint extensionPoint =
				Platform.getExtensionRegistry().getExtensionPoint(EXTENSION_POINT_ID);
		if (extensionPoint == null) return null;
		IExtension[] extensions = extensionPoint.getExtensions();
		if (extensions == null) return null;

		List<EntryDescriptor> items = new ArrayList<EntryDescriptor>();
		for (int i = 0; i < extensions.length; ++i)	{
			IConfigurationElement[] elements = extensions[i].getConfigurationElements();
			for (IConfigurationElement element : elements) {
				if (element.getName().equals(ELEMENT_NAME)) {
					CNewWizard w = null;
					try {
						w = (CNewWizard) element.createExecutableExtension(CLASS_NAME);
					} catch (CoreException e) {
						System.out.println(Message.CCFMainWizardPage_6 + e.getLocalizedMessage());
						return null;
					}
					if (w == null)
						return null;
					w.setDependentControl(right, ls);
					for (EntryDescriptor ed : w.createItems(show_sup.getSelection(), wizard))
						items.add(ed);
				}
			}
		}
		// If there is a EntryDescriptor which is default for category, make sure it
		// is in the front of the list.
		for (int i = 0; i < items.size(); ++i) {
			EntryDescriptor ed = items.get(i);
			if (ed.isDefaultForCategory()) {
				items.remove(i);
				items.add(0, ed);
				break;
			}
		}

		// bug # 211935 : allow items filtering.
		if (ls != null) // NULL means call from prefs
			items = ls.filterItems(items);
		addItemsToTree(tree, items);

		if (tree.getItemCount() > 0) {
			TreeItem target = null;
			// Try to search item which was selected before
			if (savedLabel != null) {
				target = findItem(tree, savedLabel, savedParentLabel);
			}
			if (target == null) {
				// Default selection associated with "org.eclipse.cdt.build.core.buildArtefactType.exe" project type
				target = findItem(tree, Message.CCFMainWizardPage_DefaultProjectType,
						Message.CCFMainWizardPage_DefaultProjectCategory);
				if (target == null) {
					CUIPlugin.log(new Status(IStatus.WARNING, CUIPlugin.PLUGIN_ID,
							"Default project not found in New CCF_C/CCF_C++ Project Wizard")); //$NON-NLS-1$
				}
			}
			if (target == null) {
				target = tree.getItem(0);
				if (target.getItemCount() != 0)
					target = target.getItem(0);
			}
			tree.setSelection(target);
			return (CWizardHandler)target.getData();
		}
		return null;
	}

	private static String getParentText(TreeItem item) {
		if (item == null || item.getParentItem() == null)
			return ""; //$NON-NLS-1$
		return item.getParentItem().getText();
	}

	private static TreeItem findItem(Tree tree, String label, String parentLabel) {
		for (TreeItem item : tree.getItems()) {
			TreeItem foundItem = findTreeItem(item, label, parentLabel);
			if (foundItem!=null)
				return foundItem;
		}
		return null;
	}

	private static TreeItem findTreeItem(TreeItem item, String label, String parentLabel) {
		if (item.getText().equals(label) && getParentText(item).equals(parentLabel))
			return item;

		for (TreeItem child : item.getItems()) {
			TreeItem foundItem = findTreeItem(child, label, parentLabel);
			if (foundItem!=null)
				return foundItem;
		}
		return null;
	}

	private static void addItemsToTree(Tree tree, List<EntryDescriptor> items) {
		//  Sorting is disabled because of users requests
		//	Collections.sort(items, CDTListComparator.getInstance());

		ArrayList<TreeItem> placedTreeItemsList = new ArrayList<TreeItem>(items.size());
		ArrayList<EntryDescriptor> placedEntryDescriptorsList = new ArrayList<EntryDescriptor>(items.size());
		for (EntryDescriptor wd : items) {
			if (wd.getParentId() == null) {
				wd.setPath(wd.getId());
				TreeItem ti = new TreeItem(tree, SWT.NONE);
				ti.setText(TextProcessor.process(wd.getName()));
				ti.setData(wd.getHandler());
				ti.setData(DESC, wd);
				ti.setImage(calcImage(wd));
				placedTreeItemsList.add(ti);
				placedEntryDescriptorsList.add(wd);
			}
		}
		while (true) {
			boolean found = false;
			Iterator<EntryDescriptor> it2 = items.iterator();
			while (it2.hasNext()) {
				EntryDescriptor wd1 = it2.next();
				if (wd1.getParentId() == null) continue;
				for (int i = 0; i < placedEntryDescriptorsList.size(); i++) {
					EntryDescriptor wd2 = placedEntryDescriptorsList.get(i);
					if (wd2.getId().equals(wd1.getParentId())) {
						found = true;
						wd1.setParentId(null);
						CWizardHandler h = wd2.getHandler();
						/* If neither wd1 itself, nor its parent (wd2) have a handler
						 * associated with them, and the item is not a category,
						 * then skip it. If it's category, then it's possible that
						 * children will have a handler associated with them.
						 */
						if (h == null && wd1.getHandler() == null && !wd1.isCategory())
							break;

						wd1.setPath(wd2.getPath() + "/" + wd1.getId()); //$NON-NLS-1$
						wd1.setParent(wd2);
						if (h != null) {
							if (wd1.getHandler() == null && !wd1.isCategory())
								wd1.setHandler((CWizardHandler)h.clone());
							if (!h.isApplicable(wd1))
								break;
						}

						TreeItem p = placedTreeItemsList.get(i);
						TreeItem ti = new TreeItem(p, SWT.NONE);
						ti.setText(wd1.getName());
						ti.setData(wd1.getHandler());
						ti.setData(DESC, wd1);
						ti.setImage(calcImage(wd1));
						placedTreeItemsList.add(ti);
						placedEntryDescriptorsList.add(wd1);
						break;
					}
				}
			}
			// repeat iterations until all items are placed.
			if (!found) break;
		}
		// orphan elements (with not-existing parentId) are ignored
	}

	@SuppressWarnings("restriction")
	private void switchTo(CWizardHandler h, EntryDescriptor ed) {
		if (h == null)
			h = ed.getHandler();
		if (ed.isCategory())
			h = null;
		try {
			if (h != null)
				h.initialize(ed);
		} catch (CoreException e) {
			h = null;
		}
		if (h_selected != null)
			h_selected.handleUnSelection();
		h_selected = h;
		if (h == null) {
			if (ed.isCategory()) {
				if (categorySelectedLabel == null) {
					categorySelectedLabel = new Label(right, SWT.WRAP);
					categorySelectedLabel.setText(Message.CCFMainWizardPage_7);
					right.layout();
				}
				categorySelectedLabel.setVisible(true);
			}
			return;
		}
		System.out.print(h_selected.getHeader()+" ; ");
		rightLabel.setText(h_selected.getHeader());
		if (categorySelectedLabel != null)
			categorySelectedLabel.setVisible(false);
		h_selected.handleSelection();
		h_selected.setSupportedOnly(showSup.getSelection());
	}

	public static EntryDescriptor getDescriptor(Tree tree) {
		TreeItem[] sel = tree.getSelection();
		if (sel == null || sel.length == 0)
			return null;
		return (EntryDescriptor) sel[0].getData(DESC);
	}

	public void toolChainListChanged(int count) {
		setPageComplete(validatePage());
		getWizard().getContainer().updateButtons();
	}

	public boolean isCurrent() {
		return isCurrentPage();
	}

	private static Image calcImage(EntryDescriptor ed) {
		Image image = ed.getImage();
		if (image != null)
			return image;
		if (ed.isCategory())
			return CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_SEARCHFOLDER);
		return CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_VARIABLE);
	}

	@SuppressWarnings({ "rawtypes" })
	public List filterItems(List items) {
		return items;
	}
}